Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
html, body { width: 100%; height: 100%; font-family: 'BioRhyme', serif; background: #cbd5e1; display: flex; align-items: center; justify-content: center; perspective: 300rem; } .keyboard { transform: rotateX(60deg) rotateZ(45deg); transform-style: preserve-3d; background: #1e293b; border-radius: 2rem; padding: 2rem; box-shadow: inset 1rem 1rem 0 0.4rem #94a3b8; display: flex; gap: 0 2rem; } .keyboard .shade { position: absolute; top: 0; left: 0; width: 90%; height: 5rem; background-image: linear-gradient(90deg, #94a3b8 50%, #cbd5e1); transform: rotateX(90deg) rotateX(14deg) translateX(10rem) translateY(-6rem) translateZ(-39rem); filter: blur(0.5rem); } .keyboard .cover { width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: transparent; border-radius: 2rem; box-shadow: inset -0.3rem -0.3rem 0.1rem 0.2rem #f1f5f9, inset -1rem -1rem 0 0.4rem #cbd5e1, inset -2rem -2rem 2rem -0.6rem #64748b, 0 0 #e2e8f00.3rem 0.3rem #e2e8f00.6rem 0.6rem #e2e8f00.9rem 0.9rem #e2e8f01.2rem 1.2rem #e2e8f01.5rem 1.5rem #e2e8f01.8rem 1.8rem #e2e8f02.1rem 2.1rem #e2e8f02.4rem 2.4rem #e2e8f02.7rem 2.7rem #e2e8f03rem 3rem #e2e8f03.3rem 3.3rem #e2e8f03.6rem 3.6rem #e2e8f03.9rem 3.9rem #e2e8f04.2rem 4.2rem #e2e8f04.5rem 4.5rem #e2e8f04.8rem 4.8rem #e2e8f05.1rem 5.1rem #e2e8f05.4rem 5.4rem #e2e8f05.7rem 5.7rem #e2e8f06rem 6rem #e2e8f06.3rem 6.3rem #e2e8f06.6rem 6.6rem #e2e8f06.9rem 6.9rem #e2e8f07.2rem 7.2rem #e2e8f07.5rem 7.5rem #e2e8f0, 8rem 10rem 2rem rgba(15, 23, 42, 20), 8rem 8rem 0.5rem rgba(15, 23, 42, 20); } .row { display: flex; gap: 0 2rem; } .row:not(:first-child) { filter: drop-shadow(2rem -0.5rem 0.5rem rgba(51, 65, 85, 30)); } .row:not(:first-child) .key:not(:first-child) { filter: drop-shadow(-0.5rem 0.5rem 0.5rem rgba(51, 65, 85, 30)); } .row > .key.span { flex: 1; } .row > .key.span .side { width: 120%; height: 237%; transform: rotateZ(45deg) translate(24%, -14%) skew(337deg); background-image: linear-gradient(#f1f5f9 25%, #cbd5e1 30%); } .row > .key.span .top::before { transform: translate(5%, 5%); } .row > .key.span .top::after { background-image: linear-gradient(-25deg, transparent 45%, #e2e8f0 55%); } .column { display: flex; flex-direction: column; gap: 2rem 0; } .column > .key.span { flex: 1; } .column > .key.span .side { width: 220%; height: 103%; transform: rotateZ(45deg) translate(27%, 17%) skew(22deg); background-image: linear-gradient(#fbd38d 70%, #ed8936 75%); } .column > .key.span .top::before { background-color: #f6ad55; transform: translate(5%, 5%); } .column > .key.span .top::after { background-image: linear-gradient(291deg, transparent 45%, #f6ad55 50%); } .column:not(:first-child) { filter: drop-shadow(-0.5rem 0.5rem 0.5rem rgba(51, 65, 85, 30)); } .key { position: relative; width: 6rem; height: 6rem; transform: translateX(-3rem) translateY(-3rem); transform-style: preserve-3d; user-select: none; transition: transform 0.1s ease-out; } .key.active { transform: translateX(-1rem) translateY(-1rem); } .key .char { position: absolute; font-size: 4rem; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: #64748b; text-shadow: 0.05rem 0rem 0 #94a3b8, 0.05rem 0.1rem 0 #0f172a, 0.1rem 0.05rem 0 #94a3b8, 0.1rem 0.15rem 0 #0f172a, 0.15rem 0.1rem 0 #94a3b8, 0.15rem 0.2rem 0 #0f172a, 0.2rem 0.15rem 0 #94a3b8, 0.2rem 0.25rem 0 #0f172a, 0.25rem 0.2rem 0 #94a3b8, 0.25rem 0.3rem 0 #0f172a; } .key .side { position: absolute; width: 250%; height: 140%; background-image: linear-gradient(#f1f5f9 45%, #cbd5e1 55%); border-radius: 1rem; transform: rotateZ(45deg) translate(19%, 28%); } .key .top { position: absolute; width: 100%; height: 100%; } .key .top::before { content: ''; position: absolute; width: 100%; height: 100%; background-color: #e2e8f0; border-radius: 0.8em; filter: blur(0.3rem); transform: translate(10%, 10%); } .key .top::after { content: ''; position: absolute; width: 105%; height: 105%; background-image: linear-gradient(-45deg, transparent 45%, #e2e8f0 55%); border-radius: 0.8rem; box-shadow: inset -0.2rem -0.2rem 0.5rem -0.2rem white, 0.2rem 0.2rem 0.5rem -0.2rem white; }
import React, { useState, useEffect, useRef } from 'https://cdn.skypack.dev/react'; import ReactDOM from 'https://cdn.skypack.dev/react-dom'; const useSetState = (initialState = []) => { const [state, setState] = useState(new Set(initialState)); const add = (item) => setState(state => new Set(state.add(item))); const remove = (item) => setState(state => { state.delete(item); return new Set(state); }); return { set: state, add, remove, has: char => state.has(char) }; }; const useSound = (url) => { const sound = useRef(new Audio(url)); return { play: () => sound.current.play(), stop: () => { sound.current.pause(); sound.current.currentTime = 0; } }; }; const Key = ({ char, span, active }) => { return (React.createElement("div", { className: ['key', span && 'span', active && 'active'].filter(Boolean).join(' ') }, React.createElement("div", { className: 'side' }), React.createElement("div", { className: 'top' }), React.createElement("div", { className: 'char' }, char))); }; const Column = ({ children }) => (React.createElement("div", { className: 'column' }, children)); const Row = ({ children }) => (React.createElement("div", { className: 'row' }, children)); const Keyboard = () => { // Mechanical click sound 😎 const { play, stop } = useSound('https://cdn.yoavik.com/codepen/mechanical-keyboard/keytype.mp3'); const { add, remove, has } = useSetState([]); useEffect(() => { document.addEventListener('keydown', e => { add(e.key); stop(); play(); }); document.addEventListener('keyup', e => remove(e.key)); }, []); const keys = (chars, spans = []) => chars.map((char, i) => (React.createElement(Key, { key: char, char: char, span: spans[i] || false, active: has(char) }))); return (React.createElement("div", { className: 'keyboard' }, React.createElement(Column, null, React.createElement(Row, null, keys(['7', '8', '9'])), React.createElement(Row, null, keys(['4', '5', '6'])), React.createElement(Row, null, keys(['1', '2', '3'])), React.createElement(Row, null, keys(['0', '.'], [true, false]))), React.createElement(Column, null, keys(['+', '-'], [true, true])), React.createElement("div", { className: 'shade' }), React.createElement("div", { className: 'cover' }))); }; ReactDOM.render(React.createElement(Keyboard, null), document.body);